package com.heima.article.job;

import com.alibaba.fastjson.JSON;
import com.heima.article.service.HotArticleService;
import com.heima.common.exception.CustException;
import com.heima.model.common.constants.article.HotArticleConstants;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.mess.app.AggBehaviorDTO;
import com.heima.model.mess.app.UpdateArticleMess;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Component
@Slf4j
public class UpdateHotArticleJob {

    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    HotArticleService hotArticleService;


    @XxlJob("UpdateHotArticleJob")
    public ReturnT updateHotArticleHandle(String params) {

        log.info("热文章分值更新 调度任务开始执行....");
        //  定时更新文章热度
        // 1. 获取redis 行为列表中待处理数据
        List<UpdateArticleMess> behaviorList = getUpdateArticleMesses();
        if (CollectionUtils.isEmpty(behaviorList)) {
            log.info("太冷清了，我们项目的文章 没有任何人访问~");
            return ReturnT.SUCCESS;
        }
        // 2. 将数据按照文章分组  进行聚合统计 得到待更新的数据列表
        List<AggBehaviorDTO> aggBehaviorDTOList = getAggBehaviorList(behaviorList);
        if (CollectionUtils.isEmpty(aggBehaviorDTOList)){
            log.info("太冷清了，我们项目的文章 没有任何人访问~");
            return ReturnT.SUCCESS;
        }
        // 3.  更新数据库文章分值
        aggBehaviorDTOList.forEach(hotArticleService::updateApArticle);
        return ReturnT.SUCCESS;
    }

    private List<AggBehaviorDTO> getAggBehaviorList(List<UpdateArticleMess> behaviorList) {
        List<AggBehaviorDTO> aggBehaviorDTOList = new ArrayList<>();
        Map<Long, List<UpdateArticleMess>> map = behaviorList.stream().
                collect(Collectors.groupingBy(UpdateArticleMess::getArticleId));

        map.forEach((articleId, messList) -> {
            Optional<AggBehaviorDTO> reduce = messList.stream().map(behavior -> {
                AggBehaviorDTO aggBehaviorDTO = new AggBehaviorDTO();
                aggBehaviorDTO.setArticleId(articleId);
                switch (behavior.getType()) {
                    case LIKES:
                        aggBehaviorDTO.setLike(behavior.getAdd());
                        break;
                    case VIEWS:
                        aggBehaviorDTO.setView(behavior.getAdd());
                        break;
                    case COMMENT:
                        aggBehaviorDTO.setComment(behavior.getAdd());
                        break;
                    case COLLECTION:
                        aggBehaviorDTO.setCollect(behavior.getAdd());
                        break;
                    default:
                }
                return aggBehaviorDTO;
            }).reduce((agg1, agg2) -> {
                agg1.setLike(agg1.getLike() + agg2.getLike());
                agg1.setView(agg1.getView() + agg2.getView());
                agg1.setCollect(agg1.getCollect() + agg2.getCollect());
                agg1.setComment(agg1.getComment() + agg2.getComment());
                return agg1;
            });
            // 判断是否包含聚合结果
            if (reduce.isPresent()){
                aggBehaviorDTOList.add(reduce.get());
            }
        });
        return aggBehaviorDTOList;
    }


    private List<UpdateArticleMess> getUpdateArticleMesses() {
        Long size;
        size = redisTemplate.opsForList().size(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_LIST);
        List<Object> result = redisTemplate.executePipelined(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                // 开启管道执行命令
                connection.openPipeline();
                // 获取 0 到 size-1 的所有集合数据
                connection.lRange(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_LIST.getBytes(), 0, size - 1);
                // 截断 size 到 -1 后续的集合数据
                connection.lTrim(HotArticleConstants.HOT_ARTICLE_SCORE_BEHAVIOR_LIST.getBytes(), size, -1);
                return null;
            }
        });
        if (CollectionUtils.isNotEmpty(result)) {
            List<String> list = (List<String>) result.get(0);
            return list.stream().map(str -> JSON.parseObject(str, UpdateArticleMess.class))
                    .collect(Collectors.toList());
        }
        return null;
    }
}
